package com.smart.auth.config;

import com.smart.auth.dto.MemberDto;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
import org.springframework.security.oauth2.provider.code.JdbcAuthorizationCodeServices;
import org.springframework.security.oauth2.provider.token.*;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
import org.springframework.security.rsa.crypto.KeyStoreKeyFactory;

import javax.annotation.Resource;
import java.security.KeyPair;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * @author zhangwei
 */
@Configuration
public class AuthTokenConfig {
    @Resource
    KeyPairProperties keyPairProperties;

    @Bean
    @Primary
    public JwtAccessTokenConverter accessTokenConverter(KeyPair keyPair) {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter() {
            @Override
            public OAuth2AccessToken enhance(OAuth2AccessToken token, OAuth2Authentication authentication) {
                /**
                 * Authentication 包含：
                 * principal：识别用户。使用用户名/密码进行身份验证时，这通常是的实例  UserDetails 。
                 * credentials：通常是密码。在许多情况下，将在验证用户身份后清除此内容，以确保它不会泄漏。
                 * authorities：在 GrantedAuthority 是授予用户的高级别权限。比如说角色或范围。
                 */
                MemberDto memberDto = (MemberDto) authentication.getPrincipal();
                Map<String, Object> info = new HashMap<>();
                info.put("username", memberDto.getUsername());
                info.put("memberId", memberDto.getMemberId());
                ((DefaultOAuth2AccessToken) token).setAdditionalInformation(info);
                return super.enhance(token, authentication);
            }
        };
        converter.setKeyPair(keyPair);
        return converter;
    }

    /**
     * 令牌持久化配置
     */
    @Bean
    public TokenStore tokenStore(RedisConnectionFactory redisConnectionFactory) {
        RedisTokenStore tokenStore = new RedisTokenStore(redisConnectionFactory);
        tokenStore.setPrefix("auth:token");
        return tokenStore;
    }


    /**
     * jwtToken解析器
     * 使用非对称加密算法对token签名
     *
     * @param keyPair
     * @return
     */


    /**
     * 令牌增强
     * JWT内容增强
     * JWT负载信息默认是固定的，如果想自定义添加一些额外信息，
     * 需要实现TokenEnhancer的enhance方法将附加信息添加到access_token中
     */
    @Bean
    @Primary
    public TokenEnhancerChain tokenEnhancer(JwtAccessTokenConverter jwtAccessTokenConverter) {
        TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
        tokenEnhancerChain.setTokenEnhancers(Collections.singletonList(jwtAccessTokenConverter));
        return tokenEnhancerChain;
    }

    /**
     * 从密钥库中获取密钥对
     * 公钥
     * 私钥
     *
     * @return 秘钥对
     */
    @Bean
    public KeyPair keyPair() {
        KeyStoreKeyFactory factory = new KeyStoreKeyFactory(
                new ClassPathResource(keyPairProperties.getJksFileName()), keyPairProperties.getJksFilePassword().toCharArray());
        return factory.getKeyPair(
                keyPairProperties.getJksAliasName(), keyPairProperties.getJksFilePassword().toCharArray());
    }

}